﻿using System;
using System.Collections.Generic;
using System.Text;

namespace daSemanticAnalyser
{
    using daBase.Analyser;
    using daBase.Objects.Safe;
    using daSyntaxAnalyser;
    using daSyntaxAnalyser.SyntaxTree;
    using SemanticTree;
    using daBase.Objects.AnalysisErrors;

    /// <summary>
    /// Семантический анализатор
    /// </summary>
    [AnalyserDefaultSettings("Семантический анализатор", "Невозможно установить смысловую связь между элементами!", 100, "Анализатор не в состоянии установить смысловую связь между элементами программы. Возможно программа некорректна или анализатор работает неправильно. Сообщите о данной ошибке разработчику.")]
    public class SemanticAnalyser : LayerAnalyser
    {
        /// <summary>
        /// Добавление ошибки
        /// </summary>
        /// <param name="StartInfo">информация о местоположении ошибки</param>
        /// <param name="Message">сообщение об ошибке</param>
        /// <param name="Code">участок кода, содержащий ошибку</param>
        private void AddError(TokenInfo StartInfo, string Message, string Code)
        {
            base.AddError(Message, 100, StartInfo.File, StartInfo.Line, Code, StartInfo.MetaTags, string.Empty);
        }

        // шаблон "одиночка"
        private static SemanticAnalyser instance;

        /// <summary>
        /// Единственный экземпляр класса-анализатора
        /// </summary>
        public static SemanticAnalyser Instance
        {
            get
            {
                if (instance == null)
                    instance = new SemanticAnalyser();
                return instance;
            }
        }

        // проанализированные модули, недоанализированные типы, внешне типы, методы классов, проверенные модули
        private Dictionary<UnitElement, UnitSemanticElement> analysedUnits;
        private List<IUnanalysedTypeSemanticElement> unanalysedTypes;
        private Dictionary<string, CommonTypeSemanticElement> outerTypes;
        private Dictionary<MethodSemanticElement, string> classMethods;
        private List<PropertyOptionSemanticElement> propertyOptions;
        private List<VarSemanticElement> unlinkedVars;

        /// <summary>
        /// Инициализация
        /// </summary>
        private void Initialize()
        {
            if (analysedUnits == null)
                analysedUnits = new Dictionary<UnitElement, UnitSemanticElement>();
            else analysedUnits.Clear();
            if (unanalysedTypes == null)
                unanalysedTypes = new List<IUnanalysedTypeSemanticElement>();
            else unanalysedTypes.Clear();
            if (outerTypes == null)
                outerTypes = new Dictionary<string, CommonTypeSemanticElement>();
            else outerTypes.Clear();
            if (classMethods == null)
                classMethods = new Dictionary<MethodSemanticElement, string>();
            else classMethods.Clear();
            if (propertyOptions == null)
                propertyOptions = new List<PropertyOptionSemanticElement>();
            else propertyOptions.Clear();
            if (unlinkedVars == null)
                unlinkedVars = new List<VarSemanticElement>();
            else unlinkedVars.Clear();
        }

        /// <summary>
        /// Анализ подключенного модуля
        /// </summary>
        /// <param name="Use">синтаксический элемент-подключение модуля</param>
        /// <param name="Parent">родитель создаваемого элемента</param>
        /// <returns>семантический элемент-модуль</returns>
        private UnitSemanticElement UseUnit(UseElement Use, IChildSemanticElement Parent)
        {
            if ((Use.TreeRoot != null) && (Use.TreeRoot.Root != null) && (Use.TreeRoot.Root is UnitElement))
                return Unit(Use.TreeRoot.Root as UnitElement, Parent);
            return new UnitSemanticElement(Use.Names.Join("."), Parent, Use);
        }

        /// <summary>
        /// Анализ секции подключений модулей
        /// </summary>
        /// <param name="File">файл, в котором подключены модули</param>
        /// <param name="Uses">синтаксический элемент-подключения модулей</param>
        /// <param name="IsImplementation">является ли объявление закрытым</param>
        private void AnalyseUses(FileSemanticElement File, UsesElement Uses, bool IsImplementation)
        {
            if ((Uses != null) && (Uses.Uses != null))
                foreach (UseElement unit in Uses.Uses)
                {
                    if (IsImplementation && (File is UnitSemanticElement)) (File as UnitSemanticElement).PrivateUnits.Add(UseUnit(unit, File));
                    else File.Units.Add(UseUnit(unit, File));
                }
        }

        /// <summary>
        /// Проверка существования типа с заданным именем
        /// </summary>
        /// <param name="Parent">родительский элемент</param>
        /// <param name="Name">имя типа</param>
        /// <returns>ссылка на тип</returns>
        private CommonTypeSemanticElement CheckForType(IChildSemanticElement Parent, string Name)
        {
            string name = Name.ToLower();
            if (Parent is FileSemanticElement)
            {
                FileSemanticElement file = Parent as FileSemanticElement;
                foreach (CommonTypeSemanticElement type in file.Types)
                    if (type.Name.ToLower() == name) return type;
                UnitSemanticElement unit;
                if (file is UnitSemanticElement)
                {
                    unit = file as UnitSemanticElement;
                    foreach (CommonTypeSemanticElement type in unit.PrivateTypes)
                        if (type.Name.ToLower() == name) return type;
                }
                int unitCount = file.Units.Count;
                for (int i = unitCount - 1; i > -1; i--)
                    foreach (CommonTypeSemanticElement type in file.Units[i].Types)
                        if (type.Name.ToLower() == name) return type;
            }
            else
            {
                if (Parent is FullClassTypeSemanticElement)
                {
                    FullClassTypeSemanticElement _class = Parent as FullClassTypeSemanticElement;
                    foreach (CommonTypeSemanticElement type in _class.Other.Types)
                        if (type.Name.ToLower() == name) return type;
                }
                else if (Parent is MethodSemanticElement)
                {
                    MethodSemanticElement method = Parent as MethodSemanticElement;
                    if (method.Realization != null)
                        foreach (CommonTypeSemanticElement type in method.Realization.Types)
                            if (type.Name.ToLower() == name) return type;
                }
                if (Parent.Parent != null) return CheckForType(Parent.Parent, Name);
            }
            return null;
        }

        /// <summary>
        /// Получение ссылки на тип по имени
        /// </summary>
        /// <param name="Parent">родительский элемент</param>
        /// <param name="Name">имя типа</param>
        /// <param name="SyntaxElement">соответствующий элемент синтаксического дерева</param>
        /// <param name="Type">ожидаемый вид типа</param>
        /// <returns>ссылка на тип</returns>
        private CommonTypeSemanticElement GetTypeByName(IChildSemanticElement Parent, string Name, ISyntaxTreeElement SyntaxElement, Type Type)
        {
            CommonTypeSemanticElement type = CheckForType(Parent, Name);
            if (type != null)
                return type;
            if (Type == typeof(UnanalysedClassTypeSemanticElement))
                type = new UnanalysedClassTypeSemanticElement(Name, Parent, SyntaxElement);
            if (Type == typeof(UnanalysedInterfaceTypeSemanticElement))
                type = new UnanalysedInterfaceTypeSemanticElement(Name, Parent, SyntaxElement);
            else type = new UnanalysedCommonTypeSemanticElement(Name, Parent, SyntaxElement);
            unanalysedTypes.Add(type as IUnanalysedTypeSemanticElement);
            return type;
        }

        /// <summary>
        /// Анализ общих типов
        /// </summary>
        /// <param name="Parent">родитель создаваемого элемента</param>
        /// <param name="Unit">модуль, в котором объявлен тип</param>
        /// <param name="Type">синтаксический элемент-общий тип</param>
        /// <returns>семантический элемент-общий тип</returns>
        private CommonTypeSemanticElement AnalyseCommonType(IChildSemanticElement Parent, FileSemanticElement Unit, ICommonTypeElement Type)
        {
            if (Type is EnumCommonTypeElement)
            {
                EnumCommonTypeElement type = Type as EnumCommonTypeElement;
                EnumCommonTypeSemanticElement _enum = new EnumCommonTypeSemanticElement(string.Empty, Parent, Unit, false, null, type);
                foreach (ObjectEnumCommonTypeElement value in type.Elements)
                    _enum.Values.Add(new EnumCommonTypeValueSemanticElement(value.Id.Text, _enum, value.Value, value));
                return _enum;
            }
            else if (Type is IntervalCommonTypeElement)
            {
                IntervalCommonTypeElement type = Type as IntervalCommonTypeElement;
                if ((type.Interval.End == null) && (type.Interval.Start is StandartVariableExpressionElement))
                {
                    StandartVariableExpressionElement rtype = type.Interval.Start as StandartVariableExpressionElement;
                    if ((rtype.Source == null) && (rtype.Parts.Count == 1) && ((rtype.Parts[0].Blocks == null) || (rtype.Parts[0].Blocks.Count == 0)))
                        return GetTypeByName(Parent, rtype.Parts[0].ToString(), Type, null);
                }
                return new IntervalCommonTypeSemanticElement(string.Empty, Parent, Unit, false, (Type as IntervalCommonTypeElement).Interval.Start, (Type as IntervalCommonTypeElement).Interval.End, type);
            }
            else if (Type is SetCommonTypeElement)
            {
                SetCommonTypeSemanticElement set = new SetCommonTypeSemanticElement(string.Empty, Parent, Unit, false, null, Type);
                set.Type = AnalyseCommonType(set, Unit, (Type as SetCommonTypeElement).Type);
                return set;
            }
            AddError(Type.StartInfo, "Тип не определен!", Type.ToString());
            return null;
        }

        /// <summary>
        /// Анализ константного типа
        /// </summary>
        /// <param name="Parent">родитель создаваемого элемента</param>
        /// <param name="Unit">модуль, в котором объявлен тип</param>
        /// <param name="Type">синтаксический элемент-константный тип</param>
        /// <returns>семантический элемент-общий тип</returns>
        private CommonTypeSemanticElement AnalyseConstType(IChildSemanticElement Parent, FileSemanticElement Unit, IConstTypeElement Type)
        {
            if (Type == null)
                return null;
            else if (Type is ICommonTypeElement)
                return AnalyseCommonType(Parent, Unit, Type as ICommonTypeElement);
            else if (Type is ArrayConstTypeElement)
            {
                ArrayConstTypeElement type = Type as ArrayConstTypeElement;
                ArrayConstTypeSemanticElement array = new ArrayConstTypeSemanticElement(string.Empty, Parent, Unit, false, null, null, type);
                array.Type = AnalyseConstType(array, Unit, type.Type);
                foreach (IntervalVariableExpressionElement interval in type.Intervals.Intervals)
                    array.Intervals.Add(new IntervalCommonTypeSemanticElement(string.Empty, array, Unit, false, interval.Start, interval.End, type));
                return array;
            }
            else if (Type is RecordConstTypeElement)
            {
                RecordConstTypeElement type = Type as RecordConstTypeElement;
                RecordConstTypeSemanticElement record = new RecordConstTypeSemanticElement(string.Empty, Parent, Unit, false, null, type);
                if (type.Elements != null)
                    foreach (VarDeclarationElement vars in type.Elements)
                        record.Vars.AddRange(AnalyseVarList(record, Unit, vars, DelphiTokens.Var));
                return record;
            }
            else if (Type is PackedConstTypeElement)
            {
                CommonTypeSemanticElement result = AnalyseConstType(Parent, Unit, (Type as PackedConstTypeElement).Type);
                result.Packed = true;
                return result;
            }
            AddError(Type.StartInfo, "Тип не определен!", Type.ToString());
            return null;
        }

        /// <summary>
        /// Проверка связи опции свойства с полем
        /// </summary>
        /// <param name="Vars">список переменных</param>
        /// <param name="LowerName">имя поля в нижнем регистре</param>
        /// <returns>ссылка на поле, если оно обнаружено</returns>
        private VarSemanticElement CheckForVar(List<VarSemanticElement> Vars, string LowerName)
        {
            foreach (VarSemanticElement var in Vars)
                if (var.Name.ToLower() == LowerName)
                    return var;
            return null;
        }

        /// <summary>
        /// Проверка связи опции свойства с методом
        /// </summary>
        /// <param name="Methods">список методов</param>
        /// <param name="LowerName">имя метода в нижнем регистре</param>
        /// <returns>ссылка на метод, если он обнаружен</returns>
        private MethodSemanticElement CheckForMethod(List<MethodSemanticElement> Methods, string LowerName)
        {
            foreach(MethodSemanticElement method in Methods)
                if (method.Name.ToLower() == LowerName)
                    return method;
            return null;
        }

        /// <summary>
        /// Проверка связи опции свойства с элементами интерфейса
        /// </summary>
        /// <param name="Interface">интерфейс</param>
        /// <param name="Property">свойство</param>
        /// <param name="LowerName">имя метода в нижнем регистре</param>
        /// <returns>элемент, с которым связана опция, если он был найден</returns>
        private UnitElementSemanticElement CheckForOptionLinkInInterface(InterfaceTypeSemanticElement Interface, InterfacePropertySemanticElement Property, string LowerName)
        {
            UnitElementSemanticElement result = CheckForMethod(Interface.Methods, LowerName);
            if ((result == null) && (Interface.ParentInterface != null))
                result = CheckForOptionLinkInInterface(Interface.ParentInterface, Property, LowerName);
            return result;
        }

        /// <summary>
        /// Проверка связи опции свойства с элементами класса
        /// </summary>
        /// <param name="Class">класс</param>
        /// <param name="Property">свойство</param>
        /// <param name="LowerName">имя поля или метода в нижнем регистре</param>
        /// <returns>элемент, с которым связана опция, если он был найден</returns>
        private UnitElementSemanticElement CheckForOptionLinkInClass(FullClassTypeSemanticElement Class, InterfacePropertySemanticElement Property, string LowerName)
        {
            UnitElementSemanticElement result = null;
            foreach (ClassSectionSemanticElement section in Class.Sections)
            {
                result = CheckForVar(section.Vars, LowerName);
                if (result == null) result = CheckForMethod(section.Methods, LowerName);
                if (result != null) break;
            }
            if ((result == null) && (Class.ParentClass != null) && (Class.ParentClass is FullClassTypeSemanticElement))
                result = CheckForOptionLinkInClass(Class.ParentClass as FullClassTypeSemanticElement, Property, LowerName);
            if ((result == null) && (Class.ParentInterfaces != null))
                foreach (InterfaceTypeSemanticElement _interface in Class.ParentInterfaces)
                {
                    result = CheckForOptionLinkInInterface(_interface, Property, LowerName);
                    if (result != null)
                        break;
                }
            return result;
        }

        /// <summary>
        /// Проверка связи опции свойства с другими элементами (интерфейса или класса)
        /// </summary>
        /// <param name="Property">свойство</param>
        /// <param name="LowerName">имя поля или метода в нижнем регистре</param>
        /// <returns>элемент, с которым связана опция, если он был найден</returns>
        private UnitElementSemanticElement CheckForOptionLink(InterfacePropertySemanticElement Property, string LowerName)
        {
            if (Property.Parent != null)
            {
                if (Property.Parent is InterfaceTypeSemanticElement)
                    return CheckForOptionLinkInInterface(Property.Parent as InterfaceTypeSemanticElement, Property, LowerName);
                else if ((Property.Parent.Parent != null) && (Property.Parent.Parent is FullClassTypeSemanticElement))
                    return CheckForOptionLinkInClass(Property.Parent.Parent as FullClassTypeSemanticElement, Property, LowerName);
            }
            return null;
        }

        /// <summary>
        /// Получение опции свойства
        /// </summary>
        /// <param name="Parent">родитель создаваемого элемента</param>
        /// <param name="Unit">модуль, в котором объявлена опция</param>
        /// <param name="Option">синтаксический элемент-опция свойства</param>
        /// <returns>семантический элемент-опция свойства</returns>
        private PropertyOptionSemanticElement GetPropertyOption(IChildSemanticElement Parent, FileSemanticElement Unit, PropertyOptionElement Option)
        {
            if (Option == null) return null;
            PropertyOptionTypes type;
            switch (Option.Type.Token)
            {
                case DelphiTokens.Read:
                    type = PropertyOptionTypes.Read;
                    break;
                case DelphiTokens.Write:
                    type = PropertyOptionTypes.Write;
                    break;
                case DelphiTokens.Stored:
                    type = PropertyOptionTypes.Stored;
                    break;
                case DelphiTokens.Default:
                    type = PropertyOptionTypes.Default;
                    break;
                case DelphiTokens.Nodefault:
                    type = PropertyOptionTypes.Nodefault;
                    break;
                case DelphiTokens.Dispid:
                    type = PropertyOptionTypes.Dispid;
                    break;
                default:
                    return null;
            }
            PropertyOptionSemanticElement result = new PropertyOptionSemanticElement(Parent, Unit, type, null, Option);
            switch (type)
            {
                case PropertyOptionTypes.Read:
                case PropertyOptionTypes.Write:
                    result.Value = CheckForOptionLink(Parent as InterfacePropertySemanticElement, Option.Id.ToString());
                    if (result.Value == null)
                        propertyOptions.Add(result);
                    break;
            }
            if (result.Value == null) result.Value = new UnitElementSemanticElement(Option.Id.ToString(), Parent, Unit, Option.Id);
            return result;
        }

        /// <summary>
        /// Получение типа класса
        /// </summary>
        /// <param name="Token">токен, описывающий тип</param>
        /// <returns>тип класса</returns>
        private ClassTypes GetClassType(TokenInfo Token)
        {
            if (Token == null) return ClassTypes.None;
            switch (Token.Token)
            {
                case DelphiTokens.Abstract:
                    return ClassTypes.Abstract;
                case DelphiTokens.Sealed:
                    return ClassTypes.Sealed;
                default:
                    return ClassTypes.None;
            }
        }

        /// <summary>
        /// Анализ свойства интерфейса
        /// </summary>
        /// <param name="SemanticProperty">семантический элемент-свойство интерфейса</param>
        /// <param name="Property">синтаксический элемент-свойство интерфейса</param>
        /// <returns>семантический элемент-свойство интерфейса</returns>
        private InterfacePropertySemanticElement AnalyseInterfaceProperty(InterfacePropertySemanticElement SemanticProperty, InterfacePropertyElement Property)
        {
            SemanticProperty.Name = Property.Id.Text;
            SemanticProperty.Index = (Property.Index == null) ? null : Property.Index.ToString();
            if ((Property.IndexInterval != null) && (Property.IndexInterval.Vars != null))
                foreach (FunctionVarDeclarationElement vars in Property.IndexInterval.Vars)
                    SemanticProperty.Indexes.AddRange(AnalyseVarList(SemanticProperty, SemanticProperty.Unit, vars, DelphiTokens.Var));
            SemanticProperty.Type = AnalyseType(SemanticProperty, SemanticProperty.Unit, Property.Type);
            SemanticProperty.Read = GetPropertyOption(SemanticProperty, SemanticProperty.Unit, Property.Read);
            SemanticProperty.Write = GetPropertyOption(SemanticProperty, SemanticProperty.Unit, Property.Write);
            SemanticProperty.Stored = GetPropertyOption(SemanticProperty, SemanticProperty.Unit, Property.Stored);
            SemanticProperty.Default = GetPropertyOption(SemanticProperty, SemanticProperty.Unit, Property.Default);
            return SemanticProperty;
        }

        /// <summary>
        /// Анализ свойства класса
        /// </summary>
        /// <param name="SemanticProperty">семантический элемент-свойство класса</param>
        /// <param name="Property">синтаксический элемент-свойство класса</param>
        /// <returns>семантический элемент-свойство класса</returns>
        private ClassPropertySemanticElement AnalyseClassProperty(ClassPropertySemanticElement SemanticProperty, ClassPropertyElement Property)
        {
            SemanticProperty = AnalyseInterfaceProperty(SemanticProperty, Property) as ClassPropertySemanticElement;
            SemanticProperty.Implements = GetPropertyOption(SemanticProperty, SemanticProperty.Unit, Property.Implements);
            SemanticProperty.EndDefault = Property.EndDefault;
            return SemanticProperty;
        }

        /// <summary>
        /// Анализ класса
        /// </summary>
        /// <param name="SemanticClass">семантический элемент-класс</param>
        /// <param name="Class">синтаксический элемент-класс</param>
        /// <returns>проанализированный класс</returns>
        private FullClassTypeSemanticElement AnalyseClass(FullClassTypeSemanticElement SemanticClass, FullClassDefinitionElement Class)
        {
            SemanticClass.Type = GetClassType(Class.Type);
            CommonTypeSemanticElement classtype;
            if (Class.Parents != null)
                foreach (IdElement parent in Class.Parents)
                {
                    classtype = GetTypeByName(SemanticClass.Parent, parent.Id.Text, parent, typeof(UnanalysedInterfaceTypeSemanticElement));
                    if (classtype is ClassTypeSemanticElement)
                        SemanticClass.ParentClass = classtype;
                    else SemanticClass.ParentInterfaces.Add(classtype as InterfaceTypeSemanticElement);
                }
            if (Class.Sections != null)
            {
                ClassSectionElement classsection;
                ClassSectionSemanticElement semanticsection;
                foreach (ISectionElement section in Class.Sections)
                {
                    if (section is ClassSectionElement)
                    {
                        classsection = section as ClassSectionElement;
                        if (classsection.Type == null)
                            semanticsection = SemanticClass.Published;
                        else
                            switch (classsection.Type.Token)
                            {
                                case DelphiTokens.Private:
                                    if (classsection.Strict) semanticsection = SemanticClass.StrictPrivate;
                                    else semanticsection = SemanticClass.Private;
                                    break;
                                case DelphiTokens.Protected:
                                    if (classsection.Strict) semanticsection = SemanticClass.StrictProtected;
                                    else semanticsection = SemanticClass.Protected;
                                    break;
                                case DelphiTokens.Public:
                                    semanticsection = SemanticClass.Public;
                                    break;
                                case DelphiTokens.Automated:
                                    semanticsection = SemanticClass.Automated;
                                    break;
                                default:
                                    semanticsection = SemanticClass.Published;
                                    break;
                            }
                        if (classsection.Elements != null)
                            foreach (ISectionElementElement element in classsection.Elements)
                            {
                                if (element is VarDeclarationElement)
                                    semanticsection.Vars.AddRange(AnalyseVarList(semanticsection, SemanticClass.Unit, element as VarDeclarationElement, DelphiTokens.Var));
                                else if (element is InnerProcedureHeadElement)
                                    semanticsection.Methods.Add(GetMethodHead(semanticsection, SemanticClass.Unit, element as InnerProcedureHeadElement, false));
                                else if (element is ClassMethodElement)
                                {
                                    if ((element as ClassMethodElement).Method is InnerFunctionHeadElement)
                                        semanticsection.Methods.Add(GetMethodHead(semanticsection, SemanticClass.Unit, (element as ClassMethodElement).Method as InnerFunctionHeadElement, true));
                                    else semanticsection.Methods.Add(GetMethodHead(semanticsection, SemanticClass.Unit, (element as ClassMethodElement).Method as InnerProcedureHeadElement, true));
                                }
                                else if (element is ClassPropertyElement)
                                    semanticsection.Properties.Add(AnalyseClassProperty(new ClassPropertySemanticElement(string.Empty, semanticsection, SemanticClass.Unit, null, null, null, null, null, null, null, null, false, element), element as ClassPropertyElement));
                                else AnalyseSection(semanticsection, SemanticClass.Unit, element, false);
                            }
                    }
                    else if (section is ConstDefinitionsElement)
                        AnalyseConsts(SemanticClass.Other, SemanticClass.Unit, section as ConstDefinitionsElement, false);
                    else if (section is ResourceStringDefinitionsElement)
                        AnalyseResourcestrings(SemanticClass.Other, SemanticClass.Unit, section as ResourceStringDefinitionsElement, false);
                    else if (section is TypeDeclarationsElement)
                        AnalyseTypes(SemanticClass.Other, SemanticClass.Unit, section as TypeDeclarationsElement, false);
                }
            }
            return SemanticClass;
        }

        /// <summary>
        /// Анализ типа-метода
        /// </summary>
        /// <param name="Parent">родитель</param>
        /// <param name="Unit">модуль, в котором содержится тип-метод</param>
        /// <param name="Type">синтаксический элемент-тип-метод</param>
        /// <returns>проанализированнй метод</returns>
        private MethodTypeSemanticElement AnalyseMethodType(IChildSemanticElement Parent, FileSemanticElement Unit, ProcedureTypeElement Type)
        {
            MethodTypeSemanticElement method = (Type is FunctionTypeElement) ? new FunctionTypeSemanticElement(string.Empty, Parent, Unit, false, null, Type.OfObject, null, null, Type) as MethodTypeSemanticElement : new ProcedureTypeSemanticElement(string.Empty, Parent, Unit, false, GetMethodType(Type.Type.Token), null, Type.OfObject, null, Type) as MethodTypeSemanticElement;
            if (Type.Vars != null)
            {
                string prefix;
                foreach (FunctionVarDeclarationElement vars in Type.Vars)
                {
                    prefix = (vars is PrefixedFunctionVarDeclarationElement) ? (vars as PrefixedFunctionVarDeclarationElement).Prefix.Text : null;
                    foreach (IdElement id in vars.Ids)
                        method.Params.Add(new ParamSemanticElement(id.Id.Text, method, Unit, AnalyseType(method, Unit, vars.Type), vars.IsPlatform, prefix, vars.Value, id));
                }
            }
            if (Type.Directives != null)
                foreach (DirectiveElement directive in Type.Directives)
                    method.Directives.Add(GetMethodDirective(method, directive));
            if (Type is FunctionTypeElement)
                (method as FunctionTypeSemanticElement).ReturnType = AnalyseType(method, Unit, (Type as FunctionTypeElement).ResultType);
            return method;
        }

        /// <summary>
        /// Анализ типа
        /// </summary>
        /// <param name="Parent">родитель создаваемого элемента</param>
        /// <param name="Unit">модуль, в котором объявлен тип</param>
        /// <param name="Type">синтаксический элемент-константный тип</param>
        /// <returns>семантический элемент-общий тип</returns>
        private CommonTypeSemanticElement AnalyseType(IChildSemanticElement Parent, FileSemanticElement Unit, ITypeElement Type)
        {
            if (Type is ICommonTypeElement)
                return AnalyseCommonType(Parent, Unit, Type as ICommonTypeElement);
            else if (Type is ArrayTypeElement)
            {
                ArrayTypeElement type = Type as ArrayTypeElement;
                ArrayTypeSemanticElement array = new ArrayTypeSemanticElement(string.Empty, Parent, Unit, false, null, null, type);
                array.Type = AnalyseType(array, Unit, type.Type);
                if ((type.Intervals != null) && (type.Intervals.Intervals != null))
                    foreach (IntervalVariableExpressionElement interval in type.Intervals.Intervals)
                        array.Intervals.Add(new IntervalCommonTypeSemanticElement(string.Empty, array, Unit, false, interval.Start, interval.End, interval));
                return array;
            }
            else if (Type is FileTypeElement)
            {
                FileTypeSemanticElement file = new FileTypeSemanticElement(string.Empty, Parent, Unit, false, null, Type);
                file.Type = AnalyseType(file, Unit, (Type as FileTypeElement).Type);
                return file;
            }
            else if (Type is PointerSimpleTypeElement)
            {
                PointerTypeSemanticElement pointer = new PointerTypeSemanticElement(string.Empty, Parent, Unit, false, null, Type);
                pointer.Type = GetTypeByName(pointer, (Type as PointerSimpleTypeElement).Id.Text, Type, null);
                return pointer;
            }
            else if (Type is RecordElement)
            {
                RecordElement type = Type as RecordElement;
                RecordTypeSemanticElement record = new RecordTypeSemanticElement(string.Empty, Parent, Unit, false, null, null, null, null, type);
                if (type.Elements != null)
                    foreach (ISectionElementElement element in type.Elements)
                    {
                        if (element is VarDeclarationElement)
                            record.Vars.AddRange(AnalyseVarList(record, Unit, element as VarDeclarationElement, DelphiTokens.Var));
                        else if (element is ClassPropertyElement)
                            record.Properties.Add(AnalyseClassProperty(new ClassPropertySemanticElement(string.Empty, record, Unit, null, null, null, null, null, null, null, null, false, element), element as ClassPropertyElement));
                        else if (element is InnerProcedureHeadElement)
                            record.Methods.Add(GetMethodHead(record, Unit, element as InnerProcedureHeadElement, false));
                        else if (element is RecordCaseElement)
                        {
                            RecordCaseElement _case = element as RecordCaseElement;
                            RecordCaseSemanticElement semanticcase = new RecordCaseSemanticElement(string.Empty, record, Unit, AnalyseType(record, Unit, _case.Type), null, _case);
                            RecordCaseElementSemanticElement semanticelement;
                            foreach (RecordCaseBlockElement block in _case.Blocks)
                            {
                                semanticelement = new RecordCaseElementSemanticElement(string.Empty, semanticcase, Unit, block.Params, null, block);
                                foreach (VarDeclarationElement var in block.Vars)
                                    semanticelement.Vars.AddRange(AnalyseVarList(semanticelement, Unit, var, DelphiTokens.Var));
                                semanticcase.Elements.Add(semanticelement);
                            }
                            record.Case = semanticcase;
                        }
                    }
                return record;
            }
            else if (Type is InterfaceDefinitionElement)
            {
                InterfaceDefinitionElement type = Type as InterfaceDefinitionElement;
                InterfaceTypeSemanticElement _interface = new InterfaceTypeSemanticElement(string.Empty, Parent, Unit, false, null, type.Guid, null, null, type);
                if (type.Parent != null)
                    _interface.ParentInterface = GetTypeByName(Parent, type.Parent.Id.Text, type.Parent, typeof(UnanalysedInterfaceTypeSemanticElement)) as InterfaceTypeSemanticElement;
                foreach (ISectionElementElement element in type.Elements)
                {
                    if (element is InnerProcedureHeadElement)
                        _interface.Methods.Add(GetMethodHead(_interface, Unit, element as InnerProcedureHeadElement, false));
                    else if (element is InterfacePropertyElement)
                        _interface.Properties.Add(AnalyseInterfaceProperty(new InterfacePropertySemanticElement(string.Empty, _interface, Unit, null, null, null, null, null, null, null, element), element as InterfacePropertyElement));
                }
                return _interface;
            }
            else if (Type is FullDispinterfaceDefinitionElement)
            {
                FullDispinterfaceDefinitionElement type = Type as FullDispinterfaceDefinitionElement;
                DispinterfaceTypeSemanticElement dispinterface = new DispinterfaceTypeSemanticElement(string.Empty, Parent, Unit, false, type.Guid, null, null, type);
                DispinterfacePropertyElement property;
                DispinterfacePropertySemanticElement semanticproperty;
                if (type.Elements != null)
                    foreach (ISectionElementElement element in type.Elements)
                    {
                        if (element is InnerProcedureHeadElement)
                            dispinterface.Methods.Add(GetMethodHead(dispinterface, Unit, element as InnerProcedureHeadElement, false));
                        else if (element is DispinterfacePropertyElement)
                        {
                            property = element as DispinterfacePropertyElement;
                            semanticproperty = new DispinterfacePropertySemanticElement(property.Id.Text, dispinterface, Unit, null, null, property.IsReadOnly, null, property.Default, property);
                            if ((property.IndexInterval != null) && (property.IndexInterval.Vars != null))
                                foreach (FunctionVarDeclarationElement vars in property.IndexInterval.Vars)
                                    semanticproperty.Indexes.AddRange(AnalyseVarList(semanticproperty, Unit, vars, DelphiTokens.Var));
                            semanticproperty.Type = AnalyseType(semanticproperty, Unit, property.Type);
                            semanticproperty.Dispid = GetPropertyOption(semanticproperty, Unit, property.Dispid);
                            dispinterface.Properties.Add(semanticproperty);
                        }
                    }
                return dispinterface;
            }
            else if (Type is FullClassDefinitionElement)
                return AnalyseClass(new FullClassTypeSemanticElement(string.Empty, Parent, Unit, false, ClassTypes.None, null, null, null, null, null, null, null, null, null, null, Type), Type as FullClassDefinitionElement);
            else if (Type is ClassOfDefinitionElement)
            {
                ClassOfTypeSemanticElement _class = new ClassOfTypeSemanticElement(string.Empty, Parent, Unit, false, null, Type);
                _class.Type = GetTypeByName(_class, (Type as ClassOfDefinitionElement).Id.Id.Text, (Type as ClassOfDefinitionElement).Id, null);
                return _class;
            }
            else if (Type is ObjectDefinitionElement)
                return AnalyseClass(new ObjectTypeSemanticElement(string.Empty, Parent, Unit, false, ClassTypes.None, null, null, null, null, null, null, null, null, null, null, Type), Type as ObjectDefinitionElement);
            else if (Type is ProcedureTypeElement)
                return AnalyseMethodType(Parent, Unit, Type as ProcedureTypeElement);
            else if (Type is ReferenceTypeElement)
            {
                ReferenceToMethodTypeSemanticElement reference = new ReferenceToMethodTypeSemanticElement(string.Empty, Parent, Unit, null, false, Type);
                reference.Method = AnalyseMethodType(reference, Unit, (Type as ReferenceTypeElement).Method);
                return reference;
            }
            else if (Type is PackedTypeElement)
            {
                CommonTypeSemanticElement result = AnalyseType(Parent, Unit, (Type as PackedTypeElement).Type);
                if (result.Name != string.Empty)
                    result = new SynonymCommonTypeSemanticElement(string.Empty, Parent, Unit, true, result, Type);
                else result.Packed = true;
                return result;
            }
            return null;
        }

        /// <summary>
        /// Анализ секции объявления констант
        /// </summary>
        /// <param name="Parent">родитель создаваемого элемента</param>
        /// <param name="Unit">модуль, в котором объявлены константы</param>
        /// <param name="Consts">синтаксический элемент-объявления констант</param>
        /// <param name="IsImplementation">является ли объявление закрытым</param>
        private void AnalyseConsts(ISectionedSemanticElement Parent, FileSemanticElement Unit, ConstDefinitionsElement Consts, bool IsImplementation)
        {
            ConstSemanticElement temp;
            if ((Consts != null) && (Consts.Consts != null))
                foreach (ConstDefinitionElement constant in Consts.Consts)
                {
                    temp = new ConstSemanticElement(constant.Id.Text, Parent, Unit, null, constant.Value, constant);
                    temp.Type = AnalyseConstType(Parent, Unit, constant.Type);
                    if (IsImplementation && (Parent is UnitSemanticElement)) (Parent as UnitSemanticElement).PrivateConsts.Add(temp);
                    else Parent.Consts.Add(temp);
                }
        }

        /// <summary>
        /// Анализ секции подключения строковых ресурсов
        /// </summary>
        /// <param name="Parent">родитель создаваемого элемента</param>
        /// <param name="Unit">модуль, в котором объявлены строковые ресурсы</param>
        /// <param name="Resourcestrings">синтаксический элемент-объявления строковых ресурсов</param>
        /// <param name="IsImplementation">является ли объявление закрытым</param>
        private void AnalyseResourcestrings(ISectionedSemanticElement Parent, FileSemanticElement Unit, ResourceStringDefinitionsElement Resourcestrings, bool IsImplementation)
        {
            ResourceStringSemanticElement temp;
            if ((Resourcestrings != null) && (Resourcestrings.ResourceStrings != null))
                foreach (ResourceStringDefinitionElement resourcestring in Resourcestrings.ResourceStrings)
                {
                    temp = new ResourceStringSemanticElement(resourcestring.Id.Text, Parent, Unit, resourcestring.Value, resourcestring);
                    if (IsImplementation && (Parent is UnitSemanticElement)) (Parent as UnitSemanticElement).PrivateResourcestrings.Add(temp);
                    else Parent.Resourcestrings.Add(temp);
                }
        }

        /// <summary>
        /// Анализ секции объявления типов
        /// </summary>
        /// <param name="Parent">родитель создаваемого элемента</param>
        /// <param name="Unit">модуль, в котором объявлены типы</param>
        /// <param name="Types">синтаксический элемент-объявления типов</param>
        /// <param name="IsImplementation">является ли объявление закрытым</param>
        private void AnalyseTypes(ISectionedSemanticElement Parent, FileSemanticElement Unit, TypeDeclarationsElement Types, bool IsImplementation)
        {
            CommonTypeSemanticElement temp;
            if ((Types != null) && (Types.Declarations != null))
                foreach (TypeDeclarationElement type in Types.Declarations)
                {
                    temp = AnalyseType(Parent, Unit, type.Definition);
                    if (temp == null) continue;
                    if (temp.Name != string.Empty)
                    {
                        temp = new SynonymCommonTypeSemanticElement(type.Id.Text, Parent, Unit, false, temp, type);
                        (temp as SynonymCommonTypeSemanticElement).Type.Parent = temp;
                    }
                    else temp.Name = type.Id.Text;
                    if (IsImplementation && (Parent is UnitSemanticElement)) (Parent as UnitSemanticElement).PrivateTypes.Add(temp);
                    else Parent.Types.Add(temp);
                }
        }

        /// <summary>
        /// Поиск переменной для absolute ссылки
        /// </summary>
        /// <param name="Parent">родитель ссылающейся переменной</param>
        /// <param name="Id">идентификатор переменной, на которую ссылаются</param>
        /// <returns>результат поиска</returns>
        private VarSemanticElement RawGetAbsoluteLink(IChildSemanticElement Parent, string LowerId)
        {
            if (Parent is FileSemanticElement)
            {
                FileSemanticElement file = Parent as FileSemanticElement;
                foreach (VarSemanticElement var in file.Vars)
                    if (var.Name.ToLower() == LowerId)
                        return var;
                if (Parent is UnitSemanticElement)
                {
                    UnitSemanticElement unit = Parent as UnitSemanticElement;
                    foreach (VarSemanticElement var in unit.PrivateVars)
                        if (var.Name.ToLower() == LowerId)
                            return var;
                }
            }
            else
            {
                if (Parent is RecordTypeSemanticElement)
                {
                    RecordTypeSemanticElement record = Parent as RecordTypeSemanticElement;
                    foreach (VarSemanticElement var in record.Vars)
                        if (var.Name.ToLower() == LowerId)
                            return var;
                }
                else if (Parent is ISectionedSemanticElement)
                {
                    ISectionedSemanticElement section = Parent as ISectionedSemanticElement;
                    foreach (VarSemanticElement var in section.Vars)
                        if (var.Name.ToLower() == LowerId)
                            return var;
                }
                else if (Parent is MethodSemanticElement)
                {
                    MethodSemanticElement method = Parent as MethodSemanticElement;
                    foreach (ParamSemanticElement param in method.Params)
                        if (param.Name.ToLower() == LowerId)
                            return param;
                }
                if (Parent.Parent != null) return RawGetAbsoluteLink(Parent.Parent, LowerId);
            }
            return null;
        }

        /// <summary>
        /// Поиск переменной для absolute ссылки
        /// </summary>
        /// <param name="Parent">родитель ссылающейся переменной</param>
        /// <param name="Unit">модуль, в котором объявлена ссылающаяся переменная</param>
        /// <param name="Id">идентификатор переменной, на которую ссылаются</param>
        /// <returns>результат поиска</returns>
        private VarSemanticElement GetAbsoluteLink(IChildSemanticElement Parent, FileSemanticElement Unit, string Id)
        {
            VarSemanticElement result = RawGetAbsoluteLink(Parent, Id.ToLower());
            if (result == null)
                return new UnlinkedVarSemanticElement(Id, Parent, Unit);
            return result;
        }

        /// <summary>
        /// Анализ набора объявления переменных
        /// </summary>
        /// <param name="Parent">родитель для объявленных переменных</param>
        /// <param name="Unit">модуль, в котором объявлены переменные</param>
        /// <param name="Vars">объявление переменных</param>
        /// <param name="KeyWord">ключевое слово объявления переменных</param>
        /// <returns>семантический набор объявленных переменных</returns>
        private List<VarSemanticElement> AnalyseVarList(IChildSemanticElement Parent, FileSemanticElement Unit, FunctionVarDeclarationElement Vars, DelphiTokens KeyWord)
        {
            string prefix = null;
            if (Vars is PrefixedFunctionVarDeclarationElement)
                prefix = (Vars as PrefixedFunctionVarDeclarationElement).Prefix.Text;
            CommonTypeSemanticElement type = AnalyseType(Parent, Unit, Vars.Type);
            List<VarSemanticElement> vars = new List<VarSemanticElement>();
            VarSemanticElement absolute = null;
            if (Vars.Ids != null)
            {
                if ((Vars is VarDeclarationElement) && ((Vars as VarDeclarationElement).Absolute != null))
                    absolute = GetAbsoluteLink(Parent, Unit, (Vars as VarDeclarationElement).Absolute.Id.Text);
                else absolute = null;
                foreach (IdElement id in Vars.Ids)
                {
                    if (prefix != null)
                        vars.Add(new ParamSemanticElement(id.Id.Text, Parent, Unit, type, Vars.IsPlatform, prefix, Vars.Value, id));
                    else if (KeyWord == DelphiTokens.Var)
                        vars.Add(new VarSemanticElement(id.Id.Text, Parent, Unit, type, Vars.IsPlatform, Vars.Value, absolute, id));
                    else if (KeyWord == DelphiTokens.Threadvar)
                        vars.Add(new ThreadvarSemanticElement(id.Id.Text, Parent, Unit, type, Vars.IsPlatform, Vars.Value, absolute, id));
                    if (absolute is UnlinkedVarSemanticElement)
                        unlinkedVars.Add(vars[vars.Count - 1]);
                }
            }
            return vars;
        }

        /// <summary>
        /// Анализ секции объявления переменных
        /// </summary>
        /// <param name="Parent">родитель создаваемого элемента</param>
        /// <param name="Unit">модуль, в котором объявлены переменныеы</param>
        /// <param name="Vars">синтаксический элемент-объявления переменных</param>
        /// <param name="IsImplementation">является ли объявление закрытым</param>
        private void AnalyseVars(ISectionedSemanticElement Parent, FileSemanticElement Unit, VarDeclarationsElement Vars, bool IsImplementation)
        {
            if ((Vars != null) && (Vars.Vars != null))
                foreach (VarDeclarationElement var in Vars)
                {
                    if (IsImplementation && (Parent is UnitSemanticElement))
                        (Parent as UnitSemanticElement).PrivateVars.AddRange(AnalyseVarList(Parent, Unit, var, Vars.KeyWord.Token));
                    else Parent.Vars.AddRange(AnalyseVarList(Parent, Unit, var, Vars.KeyWord.Token));
                }
        }

        /// <summary>
        /// Определение типа директивы
        /// </summary>
        /// <param name="Token">токен типа директивы</param>
        /// <returns>тип директивы</returns>
        private MethodDirectives GetMethodDirectiveType(FileSemanticElement Unit, TokenInfo Token)
        {
            switch (Token.Token)
            {
                case DelphiTokens.Local:
                    return MethodDirectives.Local;
                case DelphiTokens.Safecall:
                    return MethodDirectives.Safecall;
                case DelphiTokens.Stdcall:
                    return MethodDirectives.Stdcall;
                case DelphiTokens.Forward:
                    return MethodDirectives.Forward;
                case DelphiTokens.Far:
                    return MethodDirectives.Far;
                case DelphiTokens.Near:
                    return MethodDirectives.Near;
                case DelphiTokens.Reintroduce:
                    return MethodDirectives.Reintroduce;
                case DelphiTokens.Register:
                    return MethodDirectives.Register;
                case DelphiTokens.Cdecl:
                    return MethodDirectives.Cdecl;
                case DelphiTokens.Varargs:
                    return MethodDirectives.Varargs;
                case DelphiTokens.Static:
                    return MethodDirectives.Static;
                case DelphiTokens.Virtual:
                    return MethodDirectives.Virtual;
                case DelphiTokens.Override:
                    return MethodDirectives.Overload;
                case DelphiTokens.Abstract:
                    return MethodDirectives.Abstract;
                case DelphiTokens.Dynamic:
                    return MethodDirectives.Dynamic;
                case DelphiTokens.Overload:
                    return MethodDirectives.Overload;
                case DelphiTokens.External:
                    return MethodDirectives.External;
                case DelphiTokens.Message:
                    return MethodDirectives.Message;
                case DelphiTokens.Assembler:
                    return MethodDirectives.Assembler;
            }
            AddError(Token, "Неизвестная директива!", Token.Text);
            return MethodDirectives.Undefined;
        }

        /// <summary>
        /// Определение типа метода
        /// </summary>
        /// <param name="Type">тип метода</param>
        /// <returns>определенный тип метода</returns>
        private MethodTypes GetMethodType(DelphiTokens Type)
        {
            switch (Type)
            {
                case DelphiTokens.Constructor:
                    return MethodTypes.Constructor;
                case DelphiTokens.Destructor:
                    return MethodTypes.Destructor;
                case DelphiTokens.Function:
                    return MethodTypes.Function;
                default:
                    return MethodTypes.Procedure;
            }
        }

        /// <summary>
        /// Получение директивы метода
        /// </summary>
        /// <param name="Method">метод</param>
        /// <param name="Directive">синтаксический элемент-директива</param>
        /// <returns>семантический элемент-директива</returns>
        private MethodDirectiveSemanticElement GetMethodDirective(UnitElementSemanticElement Method, DirectiveElement Directive)
        {
            if (Directive is ExternalDirectiveElement)
            {
                ExternalDirectiveElement external = Directive as ExternalDirectiveElement;
                ExternalMethodDirectiveSemanticElement newexternal = new ExternalMethodDirectiveSemanticElement(Method, external.Name, null, external);
                if (external.Option != null)
                {
                    if (external.Option is NameExternalOptionElement)
                        newexternal.Option = new NameExternalOptionSemanticElement(newexternal, (external.Option as NameExternalOptionElement).Name, external.Option);
                    else if (external.Option is IndexExternalOptionElement)
                        newexternal.Option = new IndexExternalOptionSemanticElement(newexternal, (external.Option as IndexExternalOptionElement).Value, external.Option);
                }
                return newexternal;
            }
            else if (Directive is MessageDirectiveElement)
                return new MessageMethodDirectiveSemanticElement(Method, (Directive as MessageDirectiveElement).Message, Directive);
            else
                return new MethodDirectiveSemanticElement(Method, GetMethodDirectiveType(Method.Unit, Directive.Token), Directive);
        }

        /// <summary>
        /// Определение заголовка метода
        /// </summary>
        /// <param name="Parent">родитель создаваемого элемента</param>
        /// <param name="Unit">модуль, в котором объявлен заголовок метода</param>
        /// <param name="Method">синтаксический элемент-заголовок метода</param>
        /// <param name="IsClass">является ли метод классовым</param>
        /// <returns>семантический элемент-метод</returns>
        private MethodSemanticElement GetMethodHead(IChildSemanticElement Parent, FileSemanticElement Unit, InnerProcedureHeadElement Method, bool IsClass)
        {
            string prefix;
            MethodSemanticElement method;
            if (Method is InnerRecordClassMethodElement)
                method = new RecordClassMethodSemanticElement(Method.Id.Text, Parent, Unit, null, null, null, null, Method);
            else if (Method is DispinterfaceFunctionHeadElement)
            {
                method = new DispinterfaceFunctionSemanticElement(Method.Id.Text, Parent, Unit, null, null, null, null, null, Method);
                (method as DispinterfaceFunctionSemanticElement).Dispid = GetPropertyOption(method, Unit, (Method as DispinterfaceFunctionHeadElement).Dispid);
            }
            else if (Method is DispinterfaceProcedureHeadElement)
            {
                method = new DispinterfaceProcedureSemanticElement(Method.Id.Text, Parent, Unit, GetMethodType(Method.Type.Token), null, null, null, null, Method);
                (method as DispinterfaceProcedureSemanticElement).Dispid = GetPropertyOption(method, Unit, (Method as DispinterfaceProcedureHeadElement).Dispid);
            }
            else if (Method is InnerFunctionHeadElement)
            {
                method = new FunctionSemanticElement(Method.Id.Text, Parent, Unit, null, null, null, null, Method);
                if (IsClass) method = new ClassFunctionSemanticElement(method as FunctionSemanticElement, Method);
            }
            else
            {
                method = new ProcedureSemanticElement(Method.Id.Text, Parent, Unit, GetMethodType(Method.Type.Token), null, null, null, Method);
                if (IsClass) method = new ClassProcedureSemanticElement(method as ProcedureSemanticElement);
            }
            if (Method.Vars != null)
                foreach (FunctionVarDeclarationElement var in Method.Vars)
                {
                    prefix = (var is PrefixedFunctionVarDeclarationElement) ? (var as PrefixedFunctionVarDeclarationElement).Prefix.Text : null;
                    foreach (IdElement id in var.Ids)
                        method.Params.Add(new ParamSemanticElement(id.Id.Text, method, Unit, AnalyseType(method, Unit, var.Type), var.IsPlatform, prefix, var.Value, id));
                }
            foreach (DirectiveElement directive in Method.Directives)
                method.Directives.Add(GetMethodDirective(method, directive));
            if (Method is InnerFunctionHeadElement)
                (method as FunctionSemanticElement).ReturnType = AnalyseType(method, Unit, (Method as InnerFunctionHeadElement).ResultType);
            return method;
        }

        /// <summary>
        /// Анализ заголовка метода
        /// </summary>
        /// <param name="Parent">родитель создаваемого элемента</param>
        /// <param name="Unit">модуль, в котором объявлен заголовок метода</param>
        /// <param name="Method">синтаксический элемент-заголовок метода</param>
        /// <param name="IsImplementation">является ли объявление закрытым</param>
        private void AnalyseInnerMethod(ISectionedSemanticElement Parent, FileSemanticElement Unit, InnerProcedureHeadElement Method, bool IsImplementation)
        {
            if (IsImplementation && (Parent is UnitSemanticElement)) (Parent as UnitSemanticElement).PrivateMethods.Add(GetMethodHead(Parent, Unit, Method, false));
            else Parent.Methods.Add(GetMethodHead(Parent, Unit, Method, false));
        }

        /// <summary>
        /// Анализ метода
        /// </summary>
        /// <param name="Parent">родитель создаваемого элемента</param>
        /// <param name="Unit">модуль, в котором объявлен метод</param>
        /// <param name="Method">синтаксический элемент-метод</param>
        /// <param name="IsImplementation">является ли объявление закрытым</param>
        private void AnalyseOuterMethod(ISectionedSemanticElement Parent, FileSemanticElement Unit, OuterMethodElement Method, bool IsImplementation)
        {
            InnerProcedureHeadElement header = (Method.Header is InnerProcedureHeadElement) ? Method.Header as InnerProcedureHeadElement : (Method.Header as ClassMethodElement).Method as InnerProcedureHeadElement;
            foreach (DirectiveElement directive in header.Directives)
                if (directive.Token.Token == DelphiTokens.Forward)
                    return;
            MethodSemanticElement method = GetMethodHead(Parent, Unit, header, (Method.Header is ClassMethodElement));
            method.Realization = new MethodRealizationSemanticElement(method, Unit, null, null, null, null, null, null, (Method.Body == null) ? null : Method.Body.Statement, Method.Body);
            if ((Method.Body != null) && (Method.Body.Declarations != null))
                foreach (ISyntaxTreeElement section in Method.Body.Declarations)
                    AnalyseSection(method.Realization, Unit, section, false);
            if (IsImplementation && (Parent is UnitSemanticElement)) (Parent as UnitSemanticElement).PrivateMethods.Add(method);
            else Parent.Methods.Add(method);
            if ((header is OuterProcedureHeadElement) && ((header as OuterProcedureHeadElement).ClassName != null))
                classMethods.Add(method, (header as OuterProcedureHeadElement).ClassName.Id.Text.ToLower());
            else if ((header is OuterFunctionHeadElement) && ((header as OuterFunctionHeadElement).ClassName != null))
                classMethods.Add(method, (header as OuterFunctionHeadElement).ClassName.Id.Text.ToLower());
        }

        /// <summary>
        /// Анализ секции
        /// </summary>
        /// <param name="Parent">родитель секции</param>
        /// <param name="Unit">модуль, в котором объявлена секция</param>
        /// <param name="Section">синтаксический элемент-секция</param>
        /// <param name="IsImplementation">является ли секция закрытой</param>
        private void AnalyseSection(ISectionedSemanticElement Parent, FileSemanticElement Unit, ISyntaxTreeElement Section, bool IsImplementation)
        {
            if (Section is UsesElement)
                AnalyseUses(Unit, Section as UsesElement, IsImplementation);
            else if (Section is ConstDefinitionsElement)
                AnalyseConsts(Parent, Unit, Section as ConstDefinitionsElement, IsImplementation);
            else if (Section is ResourceStringDefinitionsElement)
                AnalyseResourcestrings(Parent, Unit, Section as ResourceStringDefinitionsElement, IsImplementation);
            else if (Section is TypeDeclarationsElement)
                AnalyseTypes(Parent, Unit, Section as TypeDeclarationsElement, IsImplementation);
            else if (Section is VarDeclarationsElement)
                AnalyseVars(Parent, Unit, Section as VarDeclarationsElement, IsImplementation);
            else if (Section is InnerProcedureHeadElement)
                AnalyseInnerMethod(Parent, Unit, Section as InnerProcedureHeadElement, IsImplementation);
            else if (Section is OuterMethodElement)
                AnalyseOuterMethod(Parent, Unit, Section as OuterMethodElement, IsImplementation);
        }

        /// <summary>
        /// Анализ файла
        /// </summary>
        /// <param name="SemanticFile">семантический элемент-файл</param>
        /// <param name="SyntaxFile">синтаксический элемент-файл</param>
        private void AnalyseFile(FileSemanticElement SemanticFile, FileElement SyntaxFile)
        {
            AnalyseUses(SemanticFile, SyntaxFile.Uses, false);
        }

        /// <summary>
        /// Проверка связей в секции констант
        /// </summary>
        /// <param name="Consts">константы</param>
        /// <param name="UnanalysedType">непроанализированный тип</param>
        /// <param name="AnalysedType">проанализированный тип</param>
        /// <returns>была ли произведена замена в данной секции</returns>
        private bool CheckConstSectionDependencies(List<ConstSemanticElement> Consts, IUnanalysedTypeSemanticElement UnanalysedType, CommonTypeSemanticElement AnalysedType)
        {
            if (Consts != null)
                foreach (ConstSemanticElement constant in Consts)
                    if (constant.Type == UnanalysedType)
                    {
                        constant.Type = AnalysedType;
                        return true;
                    }
            return false;
        }

        /// <summary>
        /// Проверка связей в секции типов
        /// </summary>
        /// <param name="Types">типы</param>
        /// <param name="UnanalysedType">непроанализированный тип</param>
        /// <param name="AnalysedType">проанализированный тип</param>
        /// <returns>была ли произведена замена в данной секции</returns>
        private bool CheckTypeSectionDependencies(List<CommonTypeSemanticElement> Types, IUnanalysedTypeSemanticElement UnanalysedType, CommonTypeSemanticElement AnalysedType)
        {
            FullClassTypeSemanticElement _class;
            if (Types != null)
                foreach (CommonTypeSemanticElement type in Types)
                    if ((type is SynonymCommonTypeSemanticElement) && ((type as SynonymCommonTypeSemanticElement).Type == UnanalysedType))
                    {
                        (type as SynonymCommonTypeSemanticElement).Type = AnalysedType;
                        return true;
                    }
                    else if ((type is InterfaceTypeSemanticElement) && ((type as InterfaceTypeSemanticElement).ParentInterface == UnanalysedType))
                    {
                        (type as InterfaceTypeSemanticElement).ParentInterface = AnalysedType as InterfaceTypeSemanticElement;
                        return true;
                    }
                    else if (type is FullClassTypeSemanticElement)
                    {
                        _class = type as FullClassTypeSemanticElement;
                        if (_class.ParentClass == UnanalysedType)
                        {
                            _class.ParentClass = AnalysedType;
                            return true;
                        }
                        if ((UnanalysedType is UnanalysedInterfaceTypeSemanticElement) && (_class.ParentInterfaces.Contains(UnanalysedType as UnanalysedInterfaceTypeSemanticElement)))
                        {
                            _class.ParentInterfaces.Insert(_class.ParentInterfaces.IndexOf(UnanalysedType as UnanalysedInterfaceTypeSemanticElement), AnalysedType as InterfaceTypeSemanticElement);
                            _class.ParentInterfaces.Remove(UnanalysedType as UnanalysedInterfaceTypeSemanticElement);
                            return true;
                        }
                    }
            return false;

        }

        /// <summary>
        /// Проверка связей в секции переменных
        /// </summary>
        /// <param name="Vars">переменные</param>
        /// <param name="UnanalysedType">непроанализированный тип</param>
        /// <param name="AnalysedType">проанализированный тип</param>
        /// <returns>была ли произведена замена в данной секции</returns>
        private bool CheckVarSectionDependencies(List<VarSemanticElement> Vars, IUnanalysedTypeSemanticElement UnanalysedType, CommonTypeSemanticElement AnalysedType)
        {
            if (Vars != null)
                foreach (VarSemanticElement var in Vars)
                    if (var.Type == UnanalysedType)
                    {
                        var.Type = AnalysedType;
                        return true;
                    }
            return false;
        }

        /// <summary>
        /// Проверка связей в секции потоковых переменных
        /// </summary>
        /// <param name="Vars">потоковые переменные</param>
        /// <param name="UnanalysedType">непроанализированный тип</param>
        /// <param name="AnalysedType">проанализированный тип</param>
        /// <returns>была ли произведена замена в данной секции</returns>
        private bool CheckThreadvarSectionDependencies(List<ThreadvarSemanticElement> Threadvars, IUnanalysedTypeSemanticElement UnanalysedType, CommonTypeSemanticElement AnalysedType)
        {
            if (Threadvars != null)
                foreach (ThreadvarSemanticElement Threadvar in Threadvars)
                    if (Threadvar.Type == UnanalysedType)
                    {
                        Threadvar.Type = AnalysedType;
                        return true;
                    }
            return false;
        }

        /// <summary>
        /// Проверка связей в секции параметров метода
        /// </summary>
        /// <param name="Vars">параметры</param>
        /// <param name="UnanalysedType">непроанализированный тип</param>
        /// <param name="AnalysedType">проанализированный тип</param>
        /// <returns>была ли произведена замена в данной секции</returns>
        private bool CheckParamSectionDependencies(List<ParamSemanticElement> Params, IUnanalysedTypeSemanticElement UnanalysedType, CommonTypeSemanticElement AnalysedType)
        {
            if (Params != null)
                foreach (ParamSemanticElement param in Params)
                    if (param.Type == UnanalysedType)
                    {
                        param.Type = AnalysedType;
                        return true;
                    }
            return false;
        }

        /// <summary>
        /// Проверка связей типов
        /// </summary>
        /// <param name="Root">корневой элемент</param>
        private void CheckTypeDependencies(FileSemanticElement Root)
        {
            string lowername;
            CommonTypeSemanticElement type;
            foreach (IUnanalysedTypeSemanticElement unanalysedtype in unanalysedTypes)
            {
                type = CheckForType(unanalysedtype.Parent, unanalysedtype.Name);
                if (type == null)
                {
                    lowername = unanalysedtype.Name.ToLower();
                    if (!outerTypes.ContainsKey(lowername))
                    {
                        if (unanalysedtype is UnanalysedClassTypeSemanticElement)
                            outerTypes.Add(lowername, new ClassTypeSemanticElement(unanalysedtype.Name, Root, null, false, null));
                        else if (unanalysedtype is UnanalysedInterfaceTypeSemanticElement)
                            outerTypes.Add(lowername, new InterfaceTypeSemanticElement(unanalysedtype.Name, Root, null, false, null, null, null, null, null));
                        else outerTypes.Add(lowername, new CommonTypeSemanticElement(unanalysedtype.Name, Root, null, false, null));
                    }
                    type = outerTypes[lowername];
                }
                bool found = false;
                if (unanalysedtype.Parent is ISectionedSemanticElement)
                {
                    ISectionedSemanticElement parent = unanalysedtype.Parent as ISectionedSemanticElement;
                    if (!CheckConstSectionDependencies(parent.Consts, unanalysedtype, type) && !CheckTypeSectionDependencies(parent.Types, unanalysedtype, type) && !CheckVarSectionDependencies(parent.Vars, unanalysedtype, type) && !CheckThreadvarSectionDependencies(parent.Threadvars, unanalysedtype, type) && (parent is UnitSemanticElement))
                    {
                        UnitSemanticElement unit = parent as UnitSemanticElement;
                        if (!CheckConstSectionDependencies(unit.PrivateConsts, unanalysedtype, type) && !CheckTypeSectionDependencies(unit.PrivateTypes, unanalysedtype, type) && !CheckVarSectionDependencies(unit.PrivateVars, unanalysedtype, type) && !CheckThreadvarSectionDependencies(unit.PrivateThreadvars, unanalysedtype, type))
                            AddError(unanalysedtype.SyntaxElement.StartInfo, "Тип не обнаружен!", unanalysedtype.Name);
                    }
                    continue;
                }
                else if (unanalysedtype.Parent is FullClassTypeSemanticElement)
                {
                    FullClassTypeSemanticElement parent = unanalysedtype.Parent as FullClassTypeSemanticElement;
                    foreach (ClassSectionSemanticElement section in parent.Sections)
                    {
                        found |= CheckVarSectionDependencies(section.Vars, unanalysedtype, type);
                        if (found) break;
                    }
                    if (!found) AddError(unanalysedtype.SyntaxElement.StartInfo, "Тип не обнаружен!", unanalysedtype.Name);
                    continue;
                }
                else if (unanalysedtype.Parent is ClassOfTypeSemanticElement)
                {
                    if ((unanalysedtype.Parent as ClassOfTypeSemanticElement).Type == unanalysedtype)
                        (unanalysedtype.Parent as ClassOfTypeSemanticElement).Type = type;
                    else AddError(unanalysedtype.SyntaxElement.StartInfo, "Тип не обнаружен!", unanalysedtype.Name);
                    continue;
                }
                else if (unanalysedtype.Parent is InterfacePropertySemanticElement)
                {
                    InterfacePropertySemanticElement parent = unanalysedtype.Parent as InterfacePropertySemanticElement;
                    if (parent.Type == unanalysedtype)
                        parent.Type = type;
                    else if (!CheckVarSectionDependencies(parent.Indexes, unanalysedtype, type)) AddError(unanalysedtype.SyntaxElement.StartInfo, "Тип не обнаружен!", unanalysedtype.Name);
                    continue;
                }
                else if (unanalysedtype.Parent is DispinterfacePropertySemanticElement)
                {
                    DispinterfacePropertySemanticElement parent = unanalysedtype.Parent as DispinterfacePropertySemanticElement;
                    if (parent.Type == unanalysedtype)
                        parent.Type = type;
                    else if (!CheckVarSectionDependencies(parent.Indexes, unanalysedtype, type)) AddError(unanalysedtype.SyntaxElement.StartInfo, "Тип не обнаружен!", unanalysedtype.Name);
                    continue;
                }
                else if (unanalysedtype.Parent is RecordTypeSemanticElement)
                {
                    if (!CheckVarSectionDependencies((unanalysedtype.Parent as RecordTypeSemanticElement).Vars, unanalysedtype, type))
                    {
                        RecordTypeSemanticElement record = unanalysedtype.Parent as RecordTypeSemanticElement;
                        if ((record.Case != null) && (record.Case.Type == unanalysedtype))
                            record.Case.Type = type;
                        else AddError(unanalysedtype.SyntaxElement.StartInfo, "Тип не обнаружен!", unanalysedtype.Name);
                    }
                    continue;
                }
                else if (unanalysedtype.Parent is RecordConstTypeSemanticElement)
                {
                    if (!CheckVarSectionDependencies((unanalysedtype.Parent as RecordConstTypeSemanticElement).Vars, unanalysedtype, type)) AddError(unanalysedtype.SyntaxElement.StartInfo, "Тип не обнаружен!", unanalysedtype.Name);
                    continue;
                }
                else if (unanalysedtype.Parent is MethodSemanticElement)
                {
                    if (!CheckParamSectionDependencies((unanalysedtype.Parent as MethodSemanticElement).Params, unanalysedtype, type))
                    {
                        if ((unanalysedtype.Parent is FunctionSemanticElement) && ((unanalysedtype.Parent as FunctionSemanticElement).ReturnType == unanalysedtype))
                            (unanalysedtype.Parent as FunctionSemanticElement).ReturnType = type;
                        else AddError(unanalysedtype.SyntaxElement.StartInfo, "Тип не обнаружен!", unanalysedtype.Name);
                    }
                    continue;
                }
                else if (unanalysedtype.Parent is MethodTypeSemanticElement)
                {
                    if (!CheckParamSectionDependencies((unanalysedtype.Parent as MethodTypeSemanticElement).Params, unanalysedtype, type))
                    {
                        if ((unanalysedtype.Parent is FunctionTypeSemanticElement) && ((unanalysedtype.Parent as FunctionTypeSemanticElement).ReturnType == unanalysedtype))
                            (unanalysedtype.Parent as FunctionTypeSemanticElement).ReturnType = type;
                        else AddError(unanalysedtype.SyntaxElement.StartInfo, "Тип не обнаружен!", unanalysedtype.Name);
                    }
                    continue;
                }
                else if (unanalysedtype.Parent is FileTypeSemanticElement)
                {
                    if ((unanalysedtype.Parent as FileTypeSemanticElement).Type == unanalysedtype)
                        (unanalysedtype.Parent as FileTypeSemanticElement).Type = type;
                    else AddError(unanalysedtype.SyntaxElement.StartInfo, "Тип не обнаружен!", unanalysedtype.Name);
                    continue;
                }
                else if (unanalysedtype.Parent is ArrayTypeSemanticElement)
                {
                    if ((unanalysedtype.Parent as ArrayTypeSemanticElement).Type == unanalysedtype)
                        (unanalysedtype.Parent as ArrayTypeSemanticElement).Type = type;
                    else AddError(unanalysedtype.SyntaxElement.StartInfo, "Тип не обнаружен!", unanalysedtype.Name);
                    continue;
                }
                else if (unanalysedtype.Parent is ArrayConstTypeSemanticElement)
                {
                    if ((unanalysedtype.Parent as ArrayConstTypeSemanticElement).Type == unanalysedtype)
                        (unanalysedtype.Parent as ArrayConstTypeSemanticElement).Type = type;
                    else AddError(unanalysedtype.SyntaxElement.StartInfo, "Тип не обнаружен!", unanalysedtype.Name);
                    continue;
                }
                else if (unanalysedtype.Parent is PointerTypeSemanticElement)
                {
                    if ((unanalysedtype.Parent as PointerTypeSemanticElement).Type == unanalysedtype)
                        (unanalysedtype.Parent as PointerTypeSemanticElement).Type = type;
                    else AddError(unanalysedtype.SyntaxElement.StartInfo, "Тип не обнаружен!", unanalysedtype.Name);
                    continue;
                }
                else if (unanalysedtype.Parent is SetCommonTypeSemanticElement)
                {
                    if ((unanalysedtype.Parent as SetCommonTypeSemanticElement).Type == unanalysedtype)
                        (unanalysedtype.Parent as SetCommonTypeSemanticElement).Type = type;
                    else AddError(unanalysedtype.SyntaxElement.StartInfo, "Тип не обнаружен!", unanalysedtype.Name);
                    continue;
                }
                else if (unanalysedtype.Parent is SynonymCommonTypeSemanticElement)
                {
                    if ((unanalysedtype.Parent as SynonymCommonTypeSemanticElement).Type == unanalysedtype)
                        (unanalysedtype.Parent as SynonymCommonTypeSemanticElement).Type = type;
                    else AddError(unanalysedtype.SyntaxElement.StartInfo, "Тип не обнаружен!", unanalysedtype.Name);
                    continue;
                }
                else if (unanalysedtype.Parent is RecordCaseElementSemanticElement)
                {
                    if (!CheckVarSectionDependencies((unanalysedtype.Parent as RecordCaseElementSemanticElement).Vars, unanalysedtype, type))
                        AddError(unanalysedtype.SyntaxElement.StartInfo, "Тип не обнаружен!", unanalysedtype.Name);
                    continue;
                }
                AddError(unanalysedtype.SyntaxElement.StartInfo, "Тип не обнаружен!", unanalysedtype.Name);
            }
            unanalysedTypes.Clear();
        }

        /// <summary>
        /// Поиск метода в класса
        /// </summary>
        /// <param name="Class">класс</param>
        /// <param name="Method">метод</param>
        /// <returns>ссылка на найденный экземпляр</returns>
        private MethodSemanticElement CheckClassForMethod(FullClassTypeSemanticElement Class, MethodSemanticElement Method)
        {
            string lowername = Method.Name.ToLower();
            bool mathch;
            int i, paramCount = Method.Params.Count;
            List<MethodSemanticElement> methods = new List<MethodSemanticElement>();
            foreach (ClassSectionSemanticElement section in Class.Sections)
                foreach (MethodSemanticElement method in section.Methods)
                    if ((method.Type == Method.Type) && (method.Name.ToLower() == lowername) && ((method.Type != MethodTypes.Function) || ((method as FunctionSemanticElement).ReturnType.GetType() == (Method as FunctionSemanticElement).ReturnType.GetType())))
                        methods.Add(method);
            if ((Method.Type != MethodTypes.Function) && (methods.Count == 1))
                return methods[0];
            foreach (MethodSemanticElement method in methods)
                if (method.Params.Count == paramCount)
                {
                    mathch = true;
                    for (i = 0; i < paramCount; i++)
                        mathch &= ((method.Params[i].Type == null) && (Method.Params[i].Type == null)) || (method.Params[i].Type.GetType() == Method.Params[i].Type.GetType());
                    if (mathch) return method;
                }
            return null;
        }

        /// <summary>
        /// Проверка связей методов
        /// </summary>
        /// <param name="Root">корневой элемент</param>
        private void CheckMethodDependencies()
        {
            MethodSemanticElement classmethod;
            int i = 0;
            foreach (MethodSemanticElement method in classMethods.Keys)
            {
                i++;
                if (i == 29)
                    i += 0;
                classmethod = null;
                foreach (CommonTypeSemanticElement type in method.Unit.Types)
                {
                    if ((type is FullClassTypeSemanticElement) && (type.Name.ToLower() == classMethods[method]))
                    {
                        classmethod = CheckClassForMethod(type as FullClassTypeSemanticElement, method);
                        if (classmethod != null) break;
                    }
                }
                if ((classmethod == null) && (method.Unit is UnitSemanticElement))
                {
                    UnitSemanticElement unit = method.Unit as UnitSemanticElement;
                    foreach (CommonTypeSemanticElement type in unit.PrivateTypes)
                        if ((type is FullClassTypeSemanticElement) && (type.Name.ToLower() == classMethods[method]))
                        {
                            classmethod = CheckClassForMethod(type as FullClassTypeSemanticElement, method);
                            if (classmethod != null) break;
                        }
                }
                if (classmethod == null) AddError(method.SyntaxElement.StartInfo, "Метод не определен!", method.Name);
                else
                {
                    if (method.Unit.Methods.Contains(method))
                        method.Unit.Methods.Remove(method);
                    else if ((method.Unit is UnitSemanticElement) && ((method.Unit as UnitSemanticElement).PrivateMethods.Contains(method)))
                        (method.Unit as UnitSemanticElement).PrivateMethods.Remove(method);
                    else AddError(method.SyntaxElement.StartInfo, "Метод не определен!", method.Name);
                    classmethod.Realization = method.Realization;
                }
            }
            classMethods.Clear();
        }

        /// <summary>
        /// Проверка связей свойств
        /// </summary>
        /// <param name="Root">корневой элемент</param>
        private void CheckPropertyDependencies()
        {
            UnitElementSemanticElement link;
            foreach (PropertyOptionSemanticElement option in propertyOptions)
            {
                link = CheckForOptionLink(option.Parent as InterfacePropertySemanticElement, option.Value.ToString().ToLower());
                if (link != null)
                    option.Value = link;
                else AddError(option.SyntaxElement.StartInfo, "Связь опции свойства не установлена!", option.SyntaxElement.ToString());
            }
            propertyOptions.Clear();
        }

        /// <summary>
        /// Поиск переменной
        /// </summary>
        /// <param name="Var">переменная, которую необходимо найти</param>
        /// <returns>результат поиска</returns>
        private VarSemanticElement CheckForAbsoluteLink(UnlinkedVarSemanticElement Var)
        {
            VarSemanticElement result = RawGetAbsoluteLink(Var.Parent, Var.Name.ToLower());
            if (result == null)
                AddError(Var.SyntaxElement.StartInfo, "Не установлена абсолюьная ссылка!", Var.SyntaxElement.ToString());
            return result;
        }

        /// <summary>
        /// Проверка связей по absolute ссылкам
        /// </summary>
        private void CheckAbsoluteDependencies()
        {
            foreach (VarSemanticElement var in unlinkedVars)
                var.AbsoluteVar = CheckForAbsoluteLink(var.AbsoluteVar as UnlinkedVarSemanticElement);
            unlinkedVars.Clear();
        }

        /// <summary>
        /// Проверка связей
        /// </summary>
        /// <param name="Root">корневой элемент</param>
        private void CheckDependencies(FileSemanticElement Root)
        {
            CheckTypeDependencies(Root);
            CheckMethodDependencies();
            CheckPropertyDependencies();
            CheckAbsoluteDependencies();
        }

        /// <summary>
        /// Анализ модуля
        /// </summary>
        /// <param name="Unit">синтаксический элемент-модуль</param>
        /// <param name="Parent">родитель модуля</param>
        /// <returns>семантический элемент-модуль</returns>
        private UnitSemanticElement Unit(UnitElement Unit, IChildSemanticElement Parent)
        {
            if (!analysedUnits.ContainsKey(Unit))
            {
                UnitSemanticElement unit = new UnitSemanticElement(Unit.Name.Id.Text, Parent, Unit);
                analysedUnits.Add(Unit, unit);
                AnalyseFile(unit, Unit);
                AnalyseTypes(unit, unit, Unit.Types, false);
                foreach (ISyntaxTreeElement _interface in Unit.Interfaces)
                    AnalyseSection(unit, unit, _interface, false);
                foreach (ISyntaxTreeElement implementation in Unit.Implementations)
                    AnalyseSection(unit, unit, implementation, true);
            }
            return analysedUnits[Unit];
        }

        /// <summary>
        /// Анализ программы (проекта)
        /// </summary>
        /// <param name="Program">синтаксический элемент-программа (проект)</param>
        /// <returns>семантический элемент-программа (проект)</returns>
        private ProgramSemanticElement Program(ProgramElement Program)
        {
            ProgramSemanticElement program = new ProgramSemanticElement(Program.Name.Id.Text, null, (Program.Params == null) ? null : Program.Params.ConvertAll<string>(x => x.Id.Text), null, null, null, null, null, null, null, Program.Compound, Program);
            AnalyseFile(program, Program);
            foreach (ISyntaxTreeElement implementation in Program.Implementations)
                AnalyseSection(program, program, implementation, false);
            return program;
        }

        /// <summary>
        /// Трансляция синтаксического дерева
        /// </summary>
        /// <param name="Root">корень синтаксического дерева</param>
        /// <returns>корень семантического дерева</returns>
        public FileSemanticElement Translate(FileElement Root)
        {
            if (Root == null)
                return null;
            file = Root.Path;
            FileSemanticElement root = null;
            try
            {
                Initialize();
                if (Root is ProgramElement)
                    root = Program(Root as ProgramElement);
                else if (Root is UnitElement)
                    root = Unit(Root as UnitElement, null);
                else if (Root is LibraryElement)
                    return null;
                CheckDependencies(root);
                return root;
            }
            catch (Exception)
            {
                AddUndefinedError(Root.StartInfo.File, 0, string.Empty, Root.StartInfo.MetaTags);
            }
            return null;
        }
    }
}
